#pragma once 

#include <system_error>
#include <string>
#include <functional>
#include "helper/sqlite/IDB.h"
#include "helper/sqlite/Statement.h"


namespace helper {
namespace sqlite {
namespace stream {


template<typename T>
class Stream {
  public:

    Stream():_db(nullptr){}
    virtual ~Stream(){
      _db = nullptr;
    }

    Stream(const Stream & ) = delete;
    Stream & operator= (const Stream & ) = delete;

    Stream(Stream && ) = delete;
    Stream & operator= (Stream && ) = delete;

    inline T & db(IDB & db) {
      if(_db != &db){
        _db = &db;
      }
      return static_cast<T&>(*this);
    }
    inline T & sql(const char * sql) {
      if(_sql != sql){
        _sql = sql;
      }
      return static_cast<T&>(*this);
    }

    typedef  std::function<std::error_code (Statement & stmt)> fbind_type;

    template<typename F>
      inline T & fbind(const F & f){
        _fbind = f;
        return static_cast<T&>(*this);
      }

    virtual T & reset() {
      _db = nullptr;
      _sql.clear();
      _fbind = nullptr;
      return static_cast<T&>(*this);
    }
  protected:

    inline IDB & db() const {
      return *_db;
    }
    inline bool isDbValid() const{
      return _db != nullptr;
    }


    inline const std::string & sql() const {
      return _sql;
    }
    inline bool isSqlValid() const{
      return _sql.size() > 0;
    }

    inline const fbind_type & fbind() const {
      return _fbind;
    }


  private:
    IDB * _db; 
    std::string _sql;
    fbind_type _fbind;
};

}//namespace stream
}//namespace sqlite
}//namespace helper
